Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(ActiveSelection): 🚀 multiple nested selection 🗂️ #7882

Closed
wants to merge 106 commits into from

Conversation

ShaMan123
Copy link
Contributor

@ShaMan123 ShaMan123 commented Apr 18, 2022

Multiple Nested Selection

This PR finalizes (so it seems) the group rewrite!

Gist

  • refactored _chooseObjectsToRender
  • made canvas hold a constant ref to ActiveSelection instead of creating new ones all time (important for devs wanting to attach events to it for customization, see fix(ActiveSelection): 🔃 preserveObjectStacking 📌 #7878)
  • introduced Group#invalidate - to handle children/ActiveSelection state changes that should propagate to group + an option for layout customization (progress - very experimental and unstable at the moment, remains optional)
  • invalidate owning group of object under ActiveSelection

The progess layout trigger is designed to enable updating group's size dynamically but it introduces unwanted changes and craziness. e.g. when object is rotating. We should consider if and how to support it. I think it should remain as is, the dev can override getLayoutStrategyResult and do what they want.

TODO

  • figure out what to do with exporters (toDataUrl, toCanvas) on group while some objects are selected and canvas.preserveObjectStacking = false and therefore not rendered by group - DONE 79db7d5
  • test/visual/golden/group-layout/selected_object.png - seems the selected rect is doubled in opacity...
  • rethink ActiveSelection caching - why not?

Dev

Video was heavy so visuals are poor but perf is amazing
ezgif com-gif-maker (1)

closes #6776

Edit fabric_app (forked)

test code to paste in the kitchensink demo
// clear canvas
canvas.clear();
 canvas.preserveObjectStacking = false;
    const circle = new fabric.Circle({ left: 100, top: 50, radius: 50 });
    const text = new fabric.Text('', { evented: false });
    const itext = new fabric.IText('Edit me\nfit-content layout', { left: 100, top: 150 });
    const g = new fabric.Group([
      new fabric.Rect({
        top: 200,
        width: 50,
        height: 50,
        fill: 'red',
        opacity: 0.3
      }),
      circle,
      itext
    ], {
      backgroundColor: 'blue',
      subTargetCheck: true,
      interactive: true
      //objectCaching: false
    });
    canvas.add(
      text,
      g
    );
    g.clone().then(clone => {
      clone.item(2).set({ text: 'Edit me\nclip path layout' });
      clone.set({
        backgroundColor: 'magenta',
        clipPath: new fabric.Circle({
          radius: 110,
          group: clone
          //left: -50, top: -50,
          // scaleX:0.6
        }),
        layout: 'clip-path'
      });
     // canvas.add(clone);
    });
    g.clone().then(clone => {
      clone.item(2).set({ text: 'Edit me\nclip path layout' });
      clone.set({
        backgroundColor: 'yellow',
        clipPath: new fabric.Circle({
          radius: 110,
          //left: -50, top: -50,
          originX: 'center', originY: 'center',
          group: clone
        }),
        layout: 'clip-path'
      });
      canvas.add(clone);
      setInterval(() => {
        clone._set('dirty', true)
      }, 0);
    });
    g.clone().then(clone => {
      clone.item(2).set({ text: 'Edit me\nabsolute positioned\nclip path layout' });
      clone.set({
        backgroundColor: '#0dcaf0',
        clipPath: new fabric.Circle({
          radius: 110, originX: 'center', originY: 'center',
          absolutePositioned: true, left: 50, top: 150, skewX:20
        }),
        layout: 'clip-path',

      });
      canvas.insertAt(clone, 0);
    });
    canvas.on('after:render', () => {
      text.set('text', `circle is on screen? ${circle.isOnScreen()}`);
      text.dirty && canvas.requestRenderAll();
    });

@github-actions
Copy link
Contributor

github-actions bot commented May 1, 2022

Code Coverage Summary

> fabric@5.1.0 coverage:report
> nyc report --reporter=lcov --reporter=text

-----------|---------|----------|---------|---------|-----------------------------------------------
File       | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s                             
-----------|---------|----------|---------|---------|-----------------------------------------------
All files  |   83.02 |    76.01 |   85.49 |   82.74 |                                               
 fabric.js |   83.02 |    76.01 |   85.49 |   82.74 | ...,30892,30966,30977-31042,31165,31264,31500 
-----------|---------|----------|---------|---------|-----------------------------------------------

Copy link
Contributor Author

@ShaMan123 ShaMan123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated from master

@github-actions
Copy link
Contributor

github-actions bot commented May 2, 2022

Code Coverage Summary

> fabric@5.1.0 coverage:report
> nyc report --reporter=lcov --reporter=text

-----------|---------|----------|---------|---------|-----------------------------------------------
File       | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s                             
-----------|---------|----------|---------|---------|-----------------------------------------------
All files  |   83.05 |    76.06 |   85.49 |   82.77 |                                               
 fabric.js |   83.05 |    76.06 |   85.49 |   82.77 | ...,30901,30975,30986-31051,31174,31273,31509 
-----------|---------|----------|---------|---------|-----------------------------------------------

@stale
Copy link

stale bot commented Jun 12, 2022

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale Issue marked as stale by the stale bot label Jun 12, 2022
@ShaMan123 ShaMan123 removed the stale Issue marked as stale by the stale bot label Jun 13, 2022
@github-actions
Copy link
Contributor

github-actions bot commented Jun 13, 2022

Code Coverage Summary

> fabric@5.1.0 coverage:report
> nyc report --reporter=lcov --reporter=text

-----------|---------|----------|---------|---------|-----------------------------------------------
File       | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s                             
-----------|---------|----------|---------|---------|-----------------------------------------------
All files  |   83.07 |    76.09 |   85.55 |   82.79 |                                               
 fabric.js |   83.07 |    76.09 |   85.55 |   82.79 | ...,30911,30985,30996-31061,31184,31283,31519 
-----------|---------|----------|---------|---------|-----------------------------------------------

@stale
Copy link

stale bot commented Jun 28, 2022

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale Issue marked as stale by the stale bot label Jun 28, 2022
@ShaMan123 ShaMan123 removed the stale Issue marked as stale by the stale bot label Jun 28, 2022
Copy link
Contributor Author

@ShaMan123 ShaMan123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

preservevObjectStacking plays a role in this PR in group rendering logic.
We can work around it, we need to think how though

if (!this.preserveObjectStacking && activeObject) {
return this._objects.filter(function (object) {
return !object.group && object !== activeObject;
}).concat(activeObject);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can stop this foolishness by doing what #8034 does on Group
I didn't touch ActiveSelection because of this piece of logic but I don't see a reason why not if we want to drop this ugly part.

this.forEachObject(function (object) {
var group = object.__owningGroup;
if (group && invalidatedGroups.indexOf(group) === -1) {
group.invalidate(invalidationContext);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe I want to add a check for objects that are group de-facto but aren't really groups:

Suggested change
group.invalidate(invalidationContext);
group.invalidate && group.invalidate(invalidationContext);

@stale
Copy link

stale bot commented Jul 30, 2022

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale Issue marked as stale by the stale bot label Jul 30, 2022
@ShaMan123 ShaMan123 removed the stale Issue marked as stale by the stale bot label Aug 1, 2022
ShaMan123 added a commit that referenced this pull request Aug 9, 2022
This allows objects on active selection to enter
I want to change that
related #7882
@ShaMan123
Copy link
Contributor Author

This PR will wait until caching is decided #7874

Copy link
Contributor Author

@ShaMan123 ShaMan123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

files to port to #8665 :

  • src/shapes/active_selection.class.js
  • src/shapes/group.class.js
  • src/shapes/object.class.js
  • test/unit/activeselection.js
  • test/unit/util.js
  • test/visual/group_layout.js - not sure what the test is

* @param {string} key
* @param {*} value
*/
_set: function (key, value) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the only part of active selection that hasn't been ported to #8665

@ShaMan123
Copy link
Contributor Author

what remains to port from this PR is caching logic and maybe a bit of rendering

Comment on lines +260 to +264
var activeObject = this.canvas && this.canvas.getActiveObject && this.canvas.getActiveObject();
// if we are adding the activeObject in a group
if (activeObject && (activeObject === object || object.isDescendantOf(activeObject))) {
this._activeObjects.push(object);
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this part....\

@ShaMan123 ShaMan123 marked this pull request as draft February 19, 2023 06:08
@asturur
Copy link
Member

asturur commented Jan 14, 2024

capturing this test case here since the functionality is not working with the current layout manager and adding an issue to describe it. The code here is not reconciliable

@ShaMan123
Copy link
Contributor Author

Reviewing the code seems we can test to see if it works because I don't see too much here that isn't in the codebase

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Create ActiveSelection with objects in group
2 participants